#ifndef __MESSAGE_SERVICE__
#define __MESSAGE_SERVICE__

#include "base.h"
#include <mutex>
#include "message.h"
#include "channel.h"

class MessageMgr
{
	friend class ServiceMgr;
	typedef std::unordered_map<uint64, MessageQueue*> MsgQueueMap;
private:
	#define CACHE_MSG_LIST_NUM 1024
	#define MSG_LIST_INDEX(handle) (handle.getValue() % CACHE_MSG_LIST_NUM)
public:
	MessageMgr() {}
	~MessageMgr();

	inline void sendMessage(const Guid64& handle, Message* msg) {
		shengine_assert(msg);
		if (msg) {
			int32 index = MSG_LIST_INDEX(handle);
			lock_[index].lock();
			_sendMessage(index, handle, msg);
			lock_[index].unlock();
		}
	}

	inline void sendMessage(CacheMsgList& msgList) {
		shengine_assert(msgList.size() > 0);
		if (msgList.size() > 0) {
			for (int32 i = 0; i < (int32)msgList.size(); i++) {
				CacheMessage& cacheMsg = msgList[i];
				int32 index = MSG_LIST_INDEX(cacheMsg.handle_);
				shengine_assert(cacheMsg.msg_);
				if (cacheMsg.msg_) {
					lock_[index].lock();
					_sendMessage(index, cacheMsg.handle_, cacheMsg.msg_);
					lock_[index].unlock();
				}
			}
		}
		msgList.clear();
	}

public:
	inline bool addMsgQueue(const Guid64& handle, MessageQueue* q) {
		shengine_assert(q);
		if (queueMap_.find(handle) == queueMap_.end()) {
			queueMap_.insert(std::make_pair(handle, q));
			return true;
		}
		else {
			shengine_assert(0);
			return false;
		}
	}

	inline bool removeMsgQueue(const Guid64& handle) {
		MsgQueueMap::iterator itr = queueMap_.find(handle);
		if (itr != queueMap_.end()) {
			queueMap_.erase(handle);
			return true;
		}
		shengine_assert(0);
		//todo log...
		return false;
	}

	inline void _sendMessage(int32 index, const Guid64& handle, Message* msg) {
		shengine_assert(msg);
		msg->retain();
		CacheMessage cacheMsg;
		cacheMsg.handle_ = handle;
		cacheMsg.msg_ = msg;
		cacheMsgList_[index].push_back(cacheMsg);
	}

	inline void _sendMessage(CacheMsgList& msgList) {
		/*for (int32 i = 0; i < msgList.size(); i++) {
			msgList[i].msg_->retain();
		}
		cacheMsgList_.insert(cacheMsgList_.end(), msgList.begin(), msgList.end());*/
	}

private:
	void process();

private:
	std::mutex lock_[CACHE_MSG_LIST_NUM];
	CacheMsgList cacheMsgList_[CACHE_MSG_LIST_NUM];
	CacheMsgList msgList_[CACHE_MSG_LIST_NUM];
	MsgQueueMap queueMap_;
};

extern MessageMgr gMessageMgr;

#endif
